iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0

函數(function)是一段可重複使用的代碼,主要執行特定的任務或計算,並可以選擇返回一個值,主要分成以下幾種:

  • 命名函式:最原始的寫法
    function greet(name) {
      console.log(`hihi~${name}`); // "hihi~kuku"
    }
    greet("kuku");
    
  • 匿名函式:沒有名字的函數,通常使用在函式表達式
    const greet = function (name) {
      console.log(`hihi~${name}`);     // "hihi~kuku"
    };
    greet("kuku");
    
  • 箭頭函式:ES6 出現的寫法,把原來的函數用較短的語法和單行函數呈現
    const greet = (name) => console.log(`hihi~${name}`);     // "hihi~kuku"
    greet("kuku");
    
  • 立即呼叫函式表達式(IIFE):顧名思義,建立後馬上執行,通常用來創建一個新的作用域,並避免污染全域命名空間。
    ((name) => console.log(`hihi~${name}`))("kuku");         // "hihi~kuku"
    
  • 高階函式:將一個或多個函數當作參數或傳回一個函數的函數,例如:map()filter()reduce()
    const newArray = [1, 2, 3].map((val) => val * 2);        // [2,4,6]
    console.log(newArray);
    
  • 建構函式:一種特殊的函式,用於創建和初始化對象實例,通常以大寫字母開頭並使用 new 關鍵字來調用。(建構子函數規劃在第 16 天分享)
    // 建構函式定義
    function Person(name, age = 18) {
      this.name = name;
      this.age = age;
    }
    
    // 使用建構函式創建對象實例
    const kuku = new Person("kuku");
    
    console.log(`名字:${kuku.name}; 年齡:${kuku.age}`);     // "名字:kuku; 年齡:18"
    

命名函數的架構

函式宣告與函式表達式(Function Expression)


函式宣告
函式宣告是一種定義函數的方式,使用 function 關鍵字來定義函數,而且這種方式可以在函數定義之前被調用,因為有 hosting。

console.log(sum(1, 2));    // 3

function sum(x, y) {
  return x + y;
}

函式表達式(Function Expression)
把函式定義為表達式,通常是把匿名函式賦值給變數,因為要執行才會賦值,所以這種宣告方式的函式內容不會在函數定義之前就可以調用。

console.log(result);      // Uncaught SyntaxError: Identifier 'result' has already been declared 

const result = function (x, y) {
  return x + y;
};

🔔 提升(hosting):
變數提升:
var 宣告的變數被提升到其作用域的頂部,並用 undefined 進行初始化

console.log(imVar); // undefined
var imVar = 6;
console.log(imVar); // 6

letconst 宣告的變數被提升,但在 TDZ(臨時死區) 中保持未初始化狀態,直到到達其宣告為止

console.log(imConst); // Uncaught ReferenceError: Cannot access 'imVar' before initialization
const imConst = 6;
console.log(imConst); // 6

函數提升: 函數宣告完全提升,而函數表達式則不以相同的方式提升

console.log(sum(1, 2));    // 3

function sum(x, y) {
  return x + y;
}

箭頭函數(Arrow Functions)


箭頭函數是 ES6 引入的一種函數定義方式,語法更簡潔。

箭頭函式的 6 種 return

  1. 不帶參數的箭頭函式,直接使用空括號
    const greet = () => "hello~";
    console.log(greet());                     // hello~
    
  2. 只有一個參數,括號可帶可不帶
    const square = x => x * x;
    console.log(square(2));                   // 4
    
  3. 2 個參數以上,需要帶括號
    const add = (a, b) => a + b;
    console.log(add(2, 3));                   // 5
    
  4. 如果需要計算或是運用很多表達式回傳特定內容,需要加上 {} 後在裡面使用 return
    const greetSomeone = name => {
      return `hello~, ${name}`;
    }
    console.log(greetSomeone(kuku));          // hello~, kuku
    
  5. 回傳物件,可以直接用括號把要回傳的物件隔開
    const getProductDetail = (product, number) => ({ product, number })
    console.log(getProductDetail(apple, 6));  // { product: 'apple', number: 6 }
    
  6. 回調函式
    const numberList = [1, 2, 3, 4];
    const square = numberList.map(num => num * num);
    console.log(square(2));                   // [1, 4, 9, 16]
    

⚠️ 語法變簡單,但是要注意:
ES6 創造箭頭函數就是用來解決傳統函數中的 this 綁定問題,所以箭頭函數沒有自己的 this,它們是從父層作用域繼承這些值的。
(關於 this 這件事規劃在第 17 天分享)

  • greet 在箭頭函數內,this 指的是父作用域

    const greet = () => console.log(this);            // Window
    
    greet();
    

    JavaScript 是物件導向設計的語法,this 往外指沒有物件,就會回到最初存在的地方 window

  • greet 物件內包一個函式 hi() 而且用函式表達式,函數中的 this.name 指的是 greet 物件

    const greet = {
      name: "kuku",
      sayHi() {
        const hi = () => console.log(this.name);      //kuku
        hi();
      }
    };
    
    greet.sayHi();
    

函數作用域與閉包


函數作用域(Function Scope)
函數作用域指的是變數在函數內部的可見範圍,只要在函數內部聲明一個變數時,這個變數只在該函數內部有效,這種作用域有助於避免變數命名衝突。

function example() {
    var localVar = 'I am local'; // 在這裡定義的變數只在函數內有效
    console.log(localVar);       // Output: I am local
}

example();
console.log(localVar);         // ReferenceError: localVar is not defined

閉包(Closures)
當一個函數在另一個函數中定義時,就會發生閉包,即使在外部函數完成執行之後,內部函數也可以存取外部函數的變數,closureFunction 保留對 outerVariable 的存取。

🔔 簡單來說,閉包就是內層函式可以取得外層函式作用域的變數。

(閉包與作用域規劃在第 18 天分享)

// closureExample 是一個函數工廠,創建和返回了一個閉包
function closureExample() {                              
  const outerVariable = "我只存活在 closureExample 中";   // outerVariable 是 closureExample 函數的局部變數

  return function () {                                   // 返回一個函數,這個函數是閉包
    console.log(outerVariable);                          // "我只存活在 closureExample 中"
  };
}

// closureFun 是一個閉包的實例
const closureFun = closureExample();                     
closureFun();

上一篇
第 3 天:操作符和控制流
下一篇
第 5 天:物件與陣列
系列文
30天 JavaScript 提升計畫:從零到精通結合2024年的創新功能30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言